package org.umlviewer.paint;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.TextAttribute;
import java.util.HashMap;
import java.util.Map;

/**
 *clase final con metodos estaticos utiles para funciones de dibujado y geometria
 * @author Rafa
 */
public final class PaintUtils {

    /***
     * dibuja la cadena centrada
     * @param g el contexto donde se pinta
     * @param s la cadena a dibujar
     * @param x la coordenada x
     * @param y la coordenada y
     * @param width el ancho del rectangulo de referencia
     */
    public static void drawCenterString(Graphics2D g, String s, int x, int y, int width)
    {        
        int stringLen =(int)g.getFontMetrics().getStringBounds(s, g).getWidth();
        int start = width/2 - stringLen/2;
        g.drawString(s, x + start, y);
    }
    
    //funcion tomada de gef
     public static void ptClosestTo(Rectangle r, Point p, Point res) {
        
        final int NORTHWEST = 0;
        final int NORTH = 1;
        final int NORTHEAST = 2;
        final int WEST = 3;
        final int CENTER = 4;
        final int EAST = 5;
        final int SOUTHWEST = 6;
        final int SOUTH = 7;
        final int SOUTHEAST = 8;
        
        int x1 = Math.min(r.x, r.x + (r.width - 1));
        int y1 = Math.min(r.y, r.y + (r.height - 1));
        int x2 = Math.max(r.x, r.x + (r.width - 1));
        int y2 = Math.max(r.y, r.y + (r.height - 1));
        int c;
        if (p.x < x1) {
            c = NORTHWEST;
        } else if (p.x > x2) {
            c = NORTHEAST;
        } else {
            c = NORTH;
        }

        if (p.y > y2) {
            c += 6;
        } else if (p.y > y1) {
            c += 3;
            if (c == CENTER) {
                int westDist = p.x - x1;
                int eastDist = x2 - p.x;
                int northDist = p.y - y1;
                int southDist = y2 - p.y;
                int shortDist;
                if (westDist < eastDist) {
                    shortDist = westDist;
                    c = WEST;
                } else {
                    shortDist = eastDist;
                    c = EAST;
                }
                if (northDist < shortDist) {
                    shortDist = northDist;
                    c = NORTH;
                }
                if (southDist < shortDist) {
                    shortDist = southDist;
                    c = SOUTH;
                }
            }
        }

        switch (c) {
        case NORTHWEST:
            res.x = x1;
            res.y = y1;
            return; // above, left
        case NORTH:
            res.x = p.x;
            res.y = y1;
            return; // above
        case NORTHEAST:
            res.x = x2;
            res.y = y1;
            return; // above, right
        case WEST:
            res.x = x1;
            res.y = p.y;
            return; // left
        case CENTER:
            res.x = p.x;
            res.y = p.y;
            return; // inside rect
        case EAST:
            res.x = x2;
            res.y = p.y;
            return; // right
        case SOUTHWEST:
            res.x = x1;
            res.y = y2;
            return; // below, left
        case SOUTH:
            res.x = p.x;
            res.y = y2;
            return; // below
        case SOUTHEAST:
            res.x = x2;
            res.y = y2;
            return; // below right
        }
    }

     //funcion tomada de gef
    /**
     * Given a Rectangle and a point, return a new Point on or in the Rectangle
     * that is closest to the given Point.
     */
    public static Point ptClosestTo(Rectangle r, Point p) {
        Point res = new Point(0, 0);
        ptClosestTo(r, p, res);
        return res;
    }
    
    /***
     * Determina la distancia entre punto, (px,py) y la linea formada por
     * (x1,y1) - (x2,y2)
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param px
     * @param py
     * @return 
     */
    public static double ptSegDist(double x1, double y1,
				   double x2, double y2,
				   double px, double py)
    {
	return Math.sqrt(ptSegDistSq(x1, y1, x2, y2, px, py));
    }
        
    private static double ptSegDistSq(double x1, double y1,
				     double x2, double y2,
				     double px, double py)
    {
	// Adjust vectors relative to x1,y1
	// x2,y2 becomes relative vector from x1,y1 to end of segment
	x2 -= x1;
	y2 -= y1;
	// px,py becomes relative vector from x1,y1 to test point
	px -= x1;
	py -= y1;
	double dotprod = px * x2 + py * y2;
	double projlenSq;
	if (dotprod <= 0.0) {
	    // px,py is on the side of x1,y1 away from x2,y2
	    // distance to segment is length of px,py vector
	    // "length of its (clipped) projection" is now 0.0
	    projlenSq = 0.0;
	} else {
	    // switch to backwards vectors relative to x2,y2
	    // x2,y2 are already the negative of x1,y1=>x2,y2
	    // to get px,py to be the negative of px,py=>x2,y2
	    // the dot product of two negated vectors is the same
	    // as the dot product of the two normal vectors
	    px = x2 - px;
	    py = y2 - py;
	    dotprod = px * x2 + py * y2;
	    if (dotprod <= 0.0) {
		// px,py is on the side of x2,y2 away from x1,y1
		// distance to segment is length of (backwards) px,py vector
		// "length of its (clipped) projection" is now 0.0
		projlenSq = 0.0;
	    } else {
		// px,py is between x1,y1 and x2,y2
		// dotprod is the length of the px,py vector
		// projected on the x2,y2=>x1,y1 vector times the
		// length of the x2,y2=>x1,y1 vector
		projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
	    }
	}
	// Distance to line is now the length of the relative point
	// vector minus the length of its projection onto the line
	// (which is zero if the projection falls outside the range
	//  of the line segment).
	double lenSq = px * px + py * py - projlenSq;
	if (lenSq < 0) {
	    lenSq = 0;
	}
	return lenSq;
    }
   
    
    public static Map<TextAttribute, Object> getUnderlineFontAtt(boolean isItalic){
        Map<TextAttribute,Object> attr = new HashMap<TextAttribute, Object>();    
        attr.put(TextAttribute.SIZE, 11);
        attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
        if(isItalic)
            attr.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
        return attr;
    }
}
